package com.dianban.plugin.weixinpay;

import com.dianban.base.ResultCode;
import com.dianban.base.ResultVo;
import com.dianban.config.redis.RedisUtil;
import com.dianban.utils.MD5Utils;
import com.dianban.weixin.util.WeiXinUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


@Component("WeixinPayFacePlugin")
public class WeixinPayFacePlugin {

    private Logger logger = LoggerFactory.getLogger(WeixinPayFacePlugin.class);

    private final String wxpayfaceAuthinfoUrl = "https://payapp.weixin.qq.com/face/get_wxpayface_authinfo";
    private final String micropayUrl ="https://api.mch.weixin.qq.com/pay/micropay";
    @Value("${weixin.appId}")
    private String appId;
    @Value("${weixin.appSecret}")
    private String appSecret;
    @Value("${weixin.mchId}")
    private String mchId;

    public ResultVo getWxpayfaceAuthinfo(String store_id, String store_name, String device_id, String rawdata,String screenMac){
        HashMap<String, Object> params = new HashMap<String,Object>();
        HashMap<String,Object> resultMap = new HashMap<String,Object>();
        String keyRedis = MD5Utils.getMD5Str(store_id+device_id+screenMac);
        Object objRedis = RedisUtil.get(keyRedis);
        if(objRedis != null){
            resultMap = (HashMap<String, Object>) objRedis;
            return ResultVo.success(resultMap,"成功");
        }
        String noncestr = WeiXinUtils.CreateNoncestr();
        String now = String.valueOf(new Date().getTime()).substring(0,10);
        params.put("store_id",store_id);//门店编号， 由商户定义， 各门店唯一。
        params.put("store_name",store_name);//门店名称，由商户定义。（可用于展示）
        params.put("device_id",device_id);//终端设备编号，由商户定义。
        params.put("rawdata",rawdata);//初始化数据。由微信人脸SDK的接口返回。
        params.put("appid",appId); //商户号绑定的公众号/小程序 appid
        params.put("mch_id",mchId); //商户号
        params.put("now",now); //取当前时间，10位unix时间戳。 例如：1239878956
        params.put("version","1"); //版本号。固定为1
        params.put("sign_type","MD5"); // 签名类型，目前支持HMAC-SHA256和MD5，默认为MD5
        params.put("nonce_str",noncestr); // 随机字符串，不长于32位
        try {
            String sign = getSign(params);
            params.put("sign",sign); // 参数签名
            String xmlParams = WeiXinUtils.getRequestXml(params);
            logger.info("xmlParams:"+xmlParams);
            HttpClient httpClient = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost(wxpayfaceAuthinfoUrl);
            httpPost.setEntity(new StringEntity(xmlParams, "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);
            String result = EntityUtils.toString(response.getEntity(), "UTF-8");
            logger.info("result:"+result);
            resultMap = WeiXinUtils.doXMLParse(result);
            String return_code = (String) resultMap.get("return_code");
            if (return_code.equals("SUCCESS")) {
                Integer expires_in = Integer.parseInt(resultMap.get("expires_in").toString()) ;
                RedisUtil.set(keyRedis,resultMap,(expires_in-60));
                return ResultVo.success(resultMap,"成功");
            }else{
                String return_msg = (String) resultMap.get("return_msg");
                return ResultVo.error(return_code,return_msg);
            }
        }catch (Exception e){
            e.printStackTrace();
            return ResultVo.error(ResultCode.FAIL);
        }
    }

    public HashMap<String, Object> getWxpayfaceCodeParams(String store_id,String authinfo){
        HashMap<String, Object> params  = new HashMap<String,Object>();
        params.put("appid",appId); //商户号绑定的公众号/小程序 appid
        params.put("mch_id",mchId); //商户号
        params.put("store_id",store_id);//门店编号， 由商户定义， 各门店唯一。
        params.put("face_authtype","FACEPAY");//FACEPAY: 人脸凭证，常用于人脸支付
        params.put("authinfo",authinfo);//调用凭证
        params.put("ask_face_permit","1");//支付成功页是否需要展示人脸识别授权项。展示：1
        params.put("face_code_type","1");//目标face_code类型，可选值："1"，刷卡付款码：18位数字，通过「付款码支付/被扫支付」接口完成支付。如果不填写则默认为"0"
        return params;
    }

    public ResultVo micropay(String store_id,String body,String out_trade_no,int total_fee,String spbill_create_ip,String auth_code){
        String noncestr = WeiXinUtils.CreateNoncestr();
        HashMap<String, Object> params = new HashMap<String,Object>();
        params.put("appid",appId); //商户号绑定的公众号/小程序 appid
        params.put("mch_id",mchId); //商户号
        params.put("device_info",store_id); //终端设备号(商户自定义，如门店编号)
        params.put("nonce_str",noncestr); // 随机字符串，不长于32位
        params.put("sign_type","MD5"); // 签名类型，目前支持HMAC-SHA256和MD5，默认为MD5
        params.put("body",body); //门店付款码	付款码支付	店名-销售商品类目	小张南山店-超市	线下门店支付
        params.put("out_trade_no",out_trade_no);//商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|*且在同一个商户号下唯一
        params.put("total_fee",total_fee);//订单总金额，单位为分，只能为整数
        params.put("spbill_create_ip",spbill_create_ip);//支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IP
        params.put("auth_code",auth_code);//扫码支付付款码，设备读取用户微信中的条码或者二维码信息 （注：用户付款码条形码规则：18位纯数字，以10、11、12、13、14、15开头）
        try {
            String sign = getSign(params);
            params.put("sign",sign); // 参数签名
            String xmlParams = WeiXinUtils.getRequestXml(params);
            logger.info("xmlParams:"+xmlParams);
            HttpClient httpClient = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost(micropayUrl);
            httpPost.setEntity(new StringEntity(xmlParams, "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);
            String result = EntityUtils.toString(response.getEntity(), "UTF-8");
            logger.info("result:"+result);
            HashMap<String,Object>  resultMap = WeiXinUtils.doXMLParse(result);
            String return_code = (String) resultMap.get("return_code");
            if (return_code.equals("SUCCESS")) {
                String result_code = (String) resultMap.get("result_code");
                if(result_code.equals("SUCCESS")) {
                    int  total_fee_result = Integer.parseInt(resultMap.get("total_fee").toString()) ;
                    if(total_fee != total_fee_result){
                        return ResultVo.error(ResultCode.ERROR,"该支付的金额："+total_fee+" 分"+"实际支付金额："+total_fee_result+ " 分");
                    }
                    Map<String, Object> returnMap = new HashMap<>();
                    BigDecimal paymentAmount = new BigDecimal(total_fee).multiply(new BigDecimal(100));
                    returnMap.put("paymentAmount", paymentAmount); //支付的微信金额
                    return ResultVo.success(returnMap,"支付成功");
                }else{
                    // SYSTEMERROR BANKERROR  USERPAYING
                    String err_code = (String) resultMap.get("err_code");
                    String err_code_des =  (String) resultMap.get("err_code_des");
                    if("SYSTEMERROR".equals(err_code) || "BANKERROR".equals(err_code) || "USERPAYING".equals(err_code)){
                        return  ResultVo.error(ResultCode.WEIXIN_PAY_UNKNOWN);
                    }
                    return ResultVo.error(err_code,err_code_des);
                }
            }else{
                String return_msg = (String) resultMap.get("return_msg");
                return ResultVo.error(return_code,return_msg);
            }
        }catch (Exception e){
            e.printStackTrace();
            return ResultVo.error(ResultCode.FAIL);
        }
    }

    /**
     * 作用：生成签名
     */
    public String getSign(HashMap<String, Object> params) throws Exception {
        // 签名步骤一：按字典序排序参数
        String str = WeiXinUtils.FormatBizQueryParaMap(params, false);
        // 签名步骤二：在string后加入KEY
        str += "&key=" + appSecret;
        // 签名步骤三：MD5加密 签名步骤四：所有字符转为大写
        str = MD5Utils.getMD5Str(str).toUpperCase();
        return str;
    }

}
